//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//


#include "precomp.h"

//
// Command ctor
//
CCommand::CCommand()
: m_pHandle(NULL),
  m_dwExecTime(EXECTIME_API_DEFAULT),
  m_szCmd(NULL),
  m_hrCmdID(0),
  m_szCmdPart2(NULL),
  m_pCMET(NULL),
  m_dwTimeout(0),
  m_pfnParse(NULL),
  m_pfnError(NULL),
  m_pParseParam(NULL),
  m_pfnPreCheck(NULL),
  m_pndNotify(NULL),
  m_dwRetriesOnError(0),
  m_dwRetryOnErrorDelay(0),
  m_apiid(APIID_NONE)
{
    // TBD_FUNCTION(CCommand::CCommand);
}


//
// Command dtor
//
CCommand::~CCommand()
{
    // TBD_FUNCTION(CCommand::~CCommand);
    delete[] m_szCmd;
    m_szCmd = NULL;
    delete[] m_szCmdPart2;
    m_szCmdPart2 = NULL;
    delete m_pndNotify;
    m_pndNotify = NULL;
    SYNCBLOCK(g_csClosing);
    if (m_pHandle) {
      m_pHandle->GetCmdList()->Remove(this);
    }
}


//
// Set the command data
//
BOOL CCommand::Init(CRilInstanceHandle* const pHandle, const LPCSTR szCmd, const LPCSTR szCmdPart2, const DWORD dwOptions,
                    const DWORD dwTimeout, CNotificationData* const pnd, const PFN_CMD_PARSE pfnParse,
                    const DWORD dwRetriesOnError, const DWORD dwRetryOnErrorDelay, const APIID apiid,
                    const PFN_CMD_ERROR pfnError, const LPVOID pParseParam, const CME_TRANSLATION *pCMET,
                    const PFN_PRE_CMD_CHECK  pfnPreCheck)
{
    //TBD_FUNCTION(CCommand::Init);
    TBD_ASSERT(0 != (dwOptions & CMDOPT_NOOP) || szCmd != NULL);

    UINT cbCmd;
    BOOL fRet = FALSE;

    if (szCmd) {
        cbCmd = strlen(szCmd) + 1;
        delete[] m_szCmd;
        m_szCmd = new char[cbCmd];
        if (!m_szCmd) {
            goto Error;
        }
        strncpyz(m_szCmd, szCmd, cbCmd);
    }

    if (szCmdPart2) {
        cbCmd = strlen(szCmdPart2) + 1;
        delete[] m_szCmdPart2;
        m_szCmdPart2 = new char[cbCmd];
        if (!m_szCmdPart2) {
            goto Error;
        }
        strncpyz(m_szCmdPart2, szCmdPart2, cbCmd);
    }
    m_pCMET = pCMET;

    m_pHandle = pHandle;
    if (m_pHandle) {
        TBD_ASSERT(pHandle->GetDevice() != NULL);
        m_hrCmdID = pHandle->GetDevice()->GetNextCmdID();
    }

    m_dwOptions = dwOptions;
    m_dwTimeout = dwTimeout;
    m_pfnParse = pfnParse;
    m_pfnError = pfnError;
    m_pParseParam = pParseParam;
    m_pfnPreCheck = pfnPreCheck;
    m_pndNotify = pnd;
    m_dwRetriesOnError = dwRetriesOnError;
    m_dwRetryOnErrorDelay = dwRetryOnErrorDelay;
    m_apiid = apiid;
    m_dwExecTime = EXECTIME_API_DEFAULT;
    fRet = TRUE;

Error:
    if (!fRet) {
        delete[] m_szCmd;
        m_szCmd = NULL;
    }
    return fRet;
}


//
//
//
BOOL CCommand::Init(CCommand* pCmd, BOOL bClone)
{
    BOOL fRet;

    //TBD_FUNCTION(CCommand::Init);
    fRet = Init(pCmd->m_pHandle, pCmd->m_szCmd, pCmd->m_szCmdPart2, pCmd->m_dwOptions, pCmd->m_dwTimeout,
                pCmd->GiveUpNotificationData(), pCmd->m_pfnParse, pCmd->m_dwRetriesOnError, pCmd->m_dwRetryOnErrorDelay, pCmd->m_apiid,
                pCmd->m_pfnError, pCmd->m_pParseParam, pCmd->m_pCMET, pCmd->m_pfnPreCheck);

    if (bClone)
        m_hrCmdID = pCmd->GetID();
    return fRet;
}


//
//
//
DWORD CCommand::GetPriority() const
{
    //TBD_FUNCTION(CCommand::GetPriority);
    DWORD dwPriority;

    if (FPower()) {
        dwPriority = CMDPRI_CRITICAL;
    } else if (FInit()) {
        dwPriority = CMDPRI_HIGHEST;
    } else if (FUrc() || IsSMSAck()) {
        dwPriority = CMDPRI_HIGH;
    } else if (FDial() || FHangup()) {
        dwPriority = CMDPRI_NORMAL;
    } else {
        dwPriority = CMDPRI_LOW;
    }
    return dwPriority;
}


void CCommand::SendResponse(const DWORD dwResponseCode, const void* const pBlob, const UINT cbBlob) const
{
    //TBD_FUNCTION(CCommand::SendResponse);
    // Are we supposed to ignore the command response?
    if (!FIgnoreRsp()) {
        // No -- send out the result as a notification
        SYNCBLOCK(g_csClosing);

        // Retrieve the owning handle
        CRilInstanceHandle* pHandle = GetHandle();

        if (pHandle && pHandle->FReadyForNotifications()) {
            // Send out the resposne to the owning handle
            pHandle->Notify(dwResponseCode, GetID(), pBlob, cbBlob);

            // Remove this command from the owning handle's command list
            pHandle->GetCmdList()->Remove(this);
        }
    }
}

//
// Requeues self in the command queue if all the
// retry attempts have not been exhausted.
//
BOOL CCommand::RetryCommandOnError(COM_PORT_TYPE PortType)
{
    //TBD_FUNCTION(CCommand::RetryCommandOnError);

    if (m_dwRetriesOnError > 0)
    {
        m_dwRetriesOnError--;
        return RequeueCmdWithDelay(PortType, this, m_dwRetryOnErrorDelay);
    }
    else
    {
        return FALSE;
    }
}

